package com.cloudfun.campusshare.controller;

import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.hutool.core.io.resource.ClassPathResource;
import cn.hutool.core.lang.UUID;
import com.cloudfun.campusshare.common.constant.Code;
import com.cloudfun.campusshare.common.constant.DeviceStatus;
import com.cloudfun.campusshare.common.constant.DeviceType;
import com.cloudfun.campusshare.common.constant.RoleType;
import com.cloudfun.campusshare.common.model.dto.ProjectDeviceImportDTO;
import com.cloudfun.campusshare.common.model.vo.*;
import com.cloudfun.campusshare.common.response.BaseResult;
import com.cloudfun.campusshare.common.response.BaseResultFactory;
import com.cloudfun.campusshare.common.response.PageResult;
import com.cloudfun.campusshare.common.security.AuthRequired;
import com.cloudfun.campusshare.common.security.AuthenticationHolder;
import com.cloudfun.campusshare.entity.DeviceEntity;
import com.cloudfun.campusshare.entity.ProjectEntity;
import com.cloudfun.campusshare.entity.UserEntity;
import com.cloudfun.campusshare.repo.ProjectEntityRepo;
import com.cloudfun.campusshare.repo.UserEntityRepo;
import com.cloudfun.campusshare.service.DeviceService;
import com.cloudfun.campusshare.service.ProjectService;
import com.cloudfun.campusshare.util.BeanCopyUtil;
import com.cloudfun.campusshare.util.ExcelUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Pageable;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.util.List;
import java.util.Optional;

/**
 * @author : ashsr.zhang
 * @date : 2020/3/3 17:17
 * @Version : v1.0
 * @description 项目接口
 **/
@RestController
@RequestMapping("/v1/project")
@Api(value = "项目中心")
@Validated
@Slf4j
@AuthRequired(role = RoleType.OPERATIONAL_MERCHANT)
public class ProjectController {
    @Autowired
    private ProjectService projectService;

    @Autowired
    private DeviceService deviceService;

    @Autowired
    private UserEntityRepo userEntityRepo;

    @Resource
    private ProjectEntityRepo projectEntityRepo;

    @ApiOperation(value = "新增项目", notes = "新增项目")
    @PostMapping("/create")
    public BaseResult createProject(@ApiParam(value = "ProjectAddVO", required = true) @Valid @RequestBody ProjectAddVO projectAddVO) {
        projectService.createProject(projectAddVO);
        return BaseResultFactory.produceEmptyResult(Code.SUCCESS);
    }

    @ApiOperation(value = "金融机构搜索商家项目")
    @GetMapping("/search/borrower-project")
    @AuthRequired(role = RoleType.FINANCIAL_INSTITUTIONS)
    public BaseResult<PageResult<ProjectListVO>> fiSearchBorrowerProject(Pageable page, @ApiParam(value = "商家Id", required = true) @RequestParam String borrowerId) {
        PageResult<ProjectListVO> projectListVOList = projectService.fiSearchBorrowerProject(page, borrowerId);
        return BaseResultFactory.produceResult(Code.SUCCESS, projectListVOList);
    }

    @ApiOperation(value = "金融机构搜索历史关联商家项目列表")
    @GetMapping("/search/history/borrower-project")
    @AuthRequired(role = RoleType.FINANCIAL_INSTITUTIONS)
    public BaseResult getBorrowerHistoryProjectList(Pageable page, @ApiParam(value = "商家Id", required = true) @RequestParam String borrowerId) {
        return BaseResultFactory.produceResult(Code.SUCCESS, projectService.getBorrowerHistoryProjectList(page, borrowerId));
    }

    @ApiOperation(value = "金融机构导出历史关联商家项目列表")
    @GetMapping("/export/history/borrower-project")
    @AuthRequired(role = RoleType.FINANCIAL_INSTITUTIONS)
    public BaseResult exportBorrowerHistoryProjectList(@ApiParam(value = "商家Id", required = true) @RequestParam String borrowerId
            , HttpServletResponse response) throws IOException {
        List<BorrowerHistoryProjectExportVO> borrowerHistoryProjectExportVOS = projectService.exportBorrowerHistoryProjectList(borrowerId);
        String enterpriseName = userEntityRepo.findById(AuthenticationHolder.getUserId()).get().getEnterpriseName();
        ExcelUtils.exportExcel(borrowerHistoryProjectExportVOS, null, "历史关联企业项目", BorrowerHistoryProjectExportVO.class,
                enterpriseName + "HistoricalAssociatedProjects", response);
        return BaseResultFactory.produceEmptyResult(Code.SUCCESS);
    }

    @ApiOperation(value = "金融机构导出商家项目")
    @PostMapping("/export/borrower-project")
    @AuthRequired(role = RoleType.FINANCIAL_INSTITUTIONS)
    public void fiExportBorrowerProject(HttpServletResponse response, @ApiParam(value = "商家Id") @RequestParam String borrowerId) throws Exception {
        long start = System.currentTimeMillis();
        List<BorrowerProjectExportVO> borrowerProjectExportVOS = projectService.fiExportBorrowerProject(borrowerId);
        log.debug("导出{}个项目耗时：{}ms", borrowerProjectExportVOS.size(), (System.currentTimeMillis() - start));
        UserEntity lender = userEntityRepo.findById(AuthenticationHolder.getUserId()).orElse(null);
        UserEntity borrower = userEntityRepo.findById(borrowerId).orElse(null);
        ExcelUtils.exportExcel(borrowerProjectExportVOS, null, "项目列表", BorrowerProjectExportVO.class,
                borrower.getEnterpriseName() + "-" + lender.getEnterpriseName() + "-AssociatedProjects", response);
    }

    @ApiOperation(value = "管理员导出商家项目")
    @PostMapping("/export/borrower-project-admin")
    @AuthRequired(role = RoleType.ADMIN)
    public void adminExportBorrowerProject(HttpServletResponse response, @ApiParam(value = "商家Id", required = true) @RequestParam String borrowerId) throws Exception {
        long start = System.currentTimeMillis();
        List<BorrowerProjectExportVO> borrowerProjectExportVOS = projectService.adminExportBorrowerProject(borrowerId);
        log.debug("导出{}个项目耗时：{}ms", borrowerProjectExportVOS.size(), (System.currentTimeMillis() - start));
        UserEntity borrower = userEntityRepo.findById(borrowerId).orElse(null);
        ExcelUtils.exportExcel(borrowerProjectExportVOS, null, "项目列表", BorrowerProjectExportVO.class,
                borrower.getEnterpriseName() + "-AssociatedProjects", response);
    }

    @ApiOperation(value = "商家、管理员搜索项目列表", notes = "项目列表")
    @GetMapping("/list")
    @AuthRequired(role = {RoleType.OPERATIONAL_MERCHANT, RoleType.ADMIN})
    public BaseResult<PageResult<ProjectListVO>> listProject(Pageable page, @ApiParam(value = "关键字") @RequestParam(required = false) String keyword,
                                                             @ApiParam(value = "商家id") @RequestParam(required = false) String userId) {
        return BaseResultFactory.produceResult(Code.SUCCESS, projectService.queryProjectList(page, keyword, userId));
    }

    @ApiOperation(value = "管理员、商家获取项目详情", notes = "管理员、商家获取项目详情")
    @GetMapping("/detail/{projectId}")
    @AuthRequired(role = {RoleType.OPERATIONAL_MERCHANT, RoleType.ADMIN})
    public BaseResult projectDetail(@ApiParam(value = "项目id", required = true) @PathVariable String projectId) {
        ProjectDetailVO projectDetail = projectService.getProjectDetail(projectId);
        return BaseResultFactory.produceResult(Code.SUCCESS, projectDetail);
    }

    @ApiOperation(value = "金融机构查看商家项目详情", notes = "金融机构查看商家项目详情")
    @GetMapping("/borrower/detail/{projectId}")
    @AuthRequired(role = RoleType.FINANCIAL_INSTITUTIONS)
    public BaseResult<ProjectDetailVO> borrowerProjectDetail(@ApiParam(value = "项目id", required = true) @PathVariable String projectId) {
        ProjectDetailVO projectDetail = projectService.borrowerProjectDetail(projectId);
        return BaseResultFactory.produceResult(Code.SUCCESS, projectDetail);
    }

    @ApiOperation(value = "项目删除", notes = "项目删除")
    @PostMapping("/delete/{projectId}")
    public BaseResult projectDelete(@ApiParam(value = "项目id", required = true) @PathVariable String projectId) {
        projectService.deleteProject(projectId);
        return BaseResultFactory.produceEmptyResult(Code.SUCCESS);
    }

    @ApiOperation(value = "设备导入excel模板下载", notes = "设备导入excel模板下载")
    @GetMapping("/model/download")
    public BaseResult modelDownload(HttpServletResponse response) {
        String userId = AuthenticationHolder.getUserId();
        ClassPathResource cpr = new ClassPathResource("/templete/" + "DeviceData.xlsx");
        InputStream in = null;

        try {
            in = cpr.getStream();
            Workbook workbook = new XSSFWorkbook(in);
            String fileName = userId + "-" + "DeviceData.xlsx";
            response.setCharacterEncoding("UTF-8");
            response.setHeader("content-Type", "application/vnd.ms-excel");
            response.setHeader("Content-Disposition",
                    "attachment;filename=\"" + URLEncoder.encode(fileName, "UTF-8") + "\"");
            workbook.write(response.getOutputStream());
            return BaseResultFactory.produceEmptyResult(Code.SUCCESS);
        } catch (Exception e) {
            e.printStackTrace();
            return BaseResultFactory.produceEmptyResult(Code.ERROR);
        }
    }

    @ApiOperation(value = "项目关联设备信息excel导入", notes = "项目关联设备信息excel导入")
    @PostMapping("/device/import/{projectId}")
    public BaseResult deviceImport(@ApiParam(value = "项目id", required = true) @PathVariable String projectId, MultipartFile file) throws Exception {
        if (file.isEmpty()) {
            return BaseResultFactory.produceEmptyResult(Code.ERROR);
        }
        ImportParams importParams = new ImportParams();
        importParams.setHeadRows(1);
        importParams.setImportFields(ProjectDeviceImportDTO.FIELDS);
        List<ProjectDeviceImportDTO> list = ExcelImportUtil.importExcel(file.getInputStream(), ProjectDeviceImportDTO.class, importParams);
        if (CollectionUtils.isEmpty(list)) {
            return BaseResultFactory.produceEmptyResult(Code.ERROR);
        }

        final String userId = AuthenticationHolder.getUserId();
        Optional<ProjectEntity> byId = projectEntityRepo.findById(projectId);
        ProjectEntity projectEntity = byId.get();
        String schoolId = projectEntity.getSchoolId();
        list.stream().filter(this::verifyExcelBlankRow).forEach(x -> {
            DeviceEntity deviceEntity = BeanCopyUtil.copy(x, DeviceEntity.class);
            deviceEntity.setUserId(userId);
            deviceEntity.setSchoolId(schoolId);
            deviceEntity.setStatus(DeviceStatus.NOT_RUNNING);
            deviceEntity.setIsUsing(true);
            deviceEntity.setOnline(false);
            if (StringUtils.isBlank(deviceEntity.getImei())) {
                deviceEntity.setImei(UUID.randomUUID().toString());
            }
            DeviceType type = DeviceType.getDeviceTypeByName(x.getDeviceType());
            if (null != type) {
                deviceEntity.setProductType(type.getProductType());
            }
            deviceEntity.setProjectId(projectId);
            deviceService.save(deviceEntity);
        });
        return BaseResultFactory.produceEmptyResult(Code.SUCCESS);
    }

    private boolean verifyExcelBlankRow(ProjectDeviceImportDTO de) {
        return !(StringUtils.isBlank(de.getDeviceName())
                && StringUtils.isBlank(de.getImei())
                && StringUtils.isBlank(de.getDeviceNumber())
                && StringUtils.isBlank(de.getDevicePlace())
                && StringUtils.isBlank(de.getDeviceType())
                && StringUtils.isBlank(de.getProductType())
                && StringUtils.isBlank(de.getLastInteractionTime())
                && StringUtils.isBlank(de.getSimCard()));
    }


    @ApiOperation(value = "根据状态查询项目名称列表", notes = "根据状态查询项目名称列表")
    @GetMapping("/status/list")
    public BaseResult listProjectName(@ApiParam(value = "项目状态", required = false) Integer status) {
        List<ProjectStatusQueryVO> projectListByStatus = projectService.getProjectListByStatus(status == null ? 0 : status);
        return BaseResultFactory.produceResult(Code.SUCCESS, projectListByStatus);
    }
}
